#include "polytope.h"
#include "error_info.h"

namespace Nesting
{

	Nesting_polygon::~Nesting_polygon()
	{
		CGAL_polygon::clear();
		update_display_list = true;
	}

	void Nesting_polygon::redraw(const GLfloat *fill_color) const
	{
		update_display_list = true;
		gl_draw(fill_color);
	}

	void Nesting_polygon::gl_draw(const GLfloat *fill_color) const
	{
		if (update_display_list)
		{
			glDeleteLists(display_list_id, 1);
			display_list_id = glGenLists(1);
			glNewList(display_list_id, GL_COMPILE);
			glLineWidth(1.0f);
			glColor3f(0.0f, 0.0f, 0.0f);
			glBegin(GL_LINE_LOOP);
			typedef CGAL_polygon::Vertex_const_iterator Con_VIter;
			for (Con_VIter it = vertices_begin(); it != vertices_end(); ++it)
				glVertex2d(it->x(), it->y());
			glEnd();

			// fill draw
			//glColor3f(0.7f, 0.7f, 0.7f);
			glColor3fv(fill_color);
			//Point c = CGAL::centroid(vertices_begin(), vertices_end(), CGAL::Dimension_tag<0>());
			//glBegin(GL_TRIANGLES);
			//for (unsigned int i = 0; i < size(); i++)
			//{
			//	glVertex2d(c.x(), c.y());
			//	glVertex2d(vertex(i).x(), vertex(i).y());
			//	glVertex2d(vertex((i+1)%size()).x(), vertex((i+1)%size()).y());
			//}
			//glEnd();

			typedef CGAL::Partition_traits_2< CGAL::Exact_predicates_inexact_constructions_kernel >::Polygon_2 Partition_polygon;

			std::list<Partition_polygon> convex_partitions;
			CGAL::approx_convex_partition_2( vertices_begin(), vertices_end(), std::back_inserter(convex_partitions) );

			for (std::list<Partition_polygon>::iterator it = convex_partitions.begin(); it != convex_partitions.end(); ++it)
			{
				glBegin(GL_POLYGON);
				for (Partition_polygon::Vertex_const_iterator vit = it->vertices_begin(); vit != it->vertices_end(); ++vit)
					glVertex2d(vit->x(), vit->y());
				glEnd();
			}
			glEndList();
			
			update_display_list = false;
		}
		glCallList(display_list_id);
	}

	void Nesting_polygon::gl_draw_bbox() const
	{
		Iso_rectangle_2 bdbox = bbox();
		glLineWidth(0.8f);
		glColor3f(1.0f, 0.0f, 0.0f);
		glLineStipple(1, 0xAAAA);
		glEnable(GL_LINE_STIPPLE);
		glBegin(GL_LINE_LOOP);
		glVertex2d(bdbox.xmin(), bdbox.ymin());
		glVertex2d(bdbox.xmax(), bdbox.ymin());
		glVertex2d(bdbox.xmax(), bdbox.ymax());
		glVertex2d(bdbox.xmin(), bdbox.ymax());
		glEnd();
		glDisable(GL_LINE_STIPPLE);
	}
	void Nesting_polygon::translate(double dx, double dy)
	{
		CGAL::Aff_transformation_2<K> trans_vec(CGAL::TRANSLATION, CGAL::Vector_2<K>(dx, dy)); 
		CGAL_polygon::operator=(CGAL::transform(trans_vec, *this));
		update_display_list = true;
	}

	void Nesting_polygon::rotate(double angle)
	{
		if (angle == 0.0)
			return;
		double rad = angle * boost::math::constants::pi<double>()/180.0;
		double s = std::sin(rad), c = std::cos(rad);
		CGAL::Aff_transformation_2<K> rot_mat(CGAL::ROTATION, s, c);
		CGAL_polygon::operator=(CGAL::transform(rot_mat, *this));
		update_display_list = true;
	}
	Nesting_polygon::Iso_rectangle_2 Nesting_polygon::bbox() const
	{
		return CGAL::bounding_box(vertices_begin(), vertices_end());
	}
	void Nesting_polygon::self_rotate(double angle)
	{
		if (angle == 0.0)
			return;
		Point_2 cent = CGAL::centroid(vertices_begin(), vertices_end(), CGAL::Dimension_tag<0>());
		CGAL::Aff_transformation_2<K> trans(CGAL::TRANSLATION, CGAL::Vector_2<K>(cent, CGAL::ORIGIN));
		double rad = angle * boost::math::constants::pi<double>()/180.0;
		double s = std::sin(rad), c = std::cos(rad);
		CGAL::Aff_transformation_2<K> rot(CGAL::ROTATION, s, c);
		CGAL::Aff_transformation_2<K> back(CGAL::TRANSLATION, CGAL::Vector_2<K>(CGAL::ORIGIN, cent));
		CGAL::Aff_transformation_2<K> m = back * (rot * trans);
		CGAL_polygon::operator=(CGAL::transform(m, *this));
		update_display_list = true;
	}
}